﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using AxeFrog.Security;

namespace AxeFrog.Web.Controllers
{
	public class StandardAccountController : BaseController
	{
		private readonly IAccountAccessHandler _accountHandler;

		public StandardAccountController(IAccountAccessHandler accountHandler)
		{
			_accountHandler = accountHandler;
		}

		public virtual ActionResult Logout()
		{
			CurrentUser.Logout();
			return RedirectToAction("Index", "Home");
		}

		public virtual ActionResult Login()
		{
			if(CurrentUser.AccessLevel > AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");

			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		public virtual ActionResult Login(string username, string password, string r)
		{
			if(CurrentUser.AccessLevel > AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");

			User user;
			if(!CurrentUser.Login(username, password))
				return RedirectToAction(false, "Invalid username or password", "Login");

			if(!string.IsNullOrEmpty(r))
				return Redirect(r);
			return RedirectToAction("Index", "Home");
		}

		public virtual ActionResult CreatePassword()
		{
			if(CurrentUser.AccessLevel == AccessLevel.Anonymous || (CurrentUser.User.Password.Length > 0 && CurrentUser.User.DecryptPassword(WebsiteSettings.PrivateKey).Length > 0))
				return RedirectToAction("Index", "Home");

			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		public virtual ActionResult CreatePassword(string pw1, string pw2, string r)
		{
			if(CurrentUser.AccessLevel == AccessLevel.Anonymous)
				return RedirectToLogin(false);

			if(pw1.Length < 5)
				ModelState.AddModelError("pw1", "The password must be at least 5 characters in length");
			else if(pw1 != pw2)
				ModelState.AddModelError("pw1", "Both password fields must contain the same value");

			if(ModelState.IsValid)
			{
				CurrentUser.User.SetPassword(pw1, WebsiteSettings.PublicKey);
				if(CurrentUser.ChangePassword(pw1))
				{
					if(!string.IsNullOrEmpty(r))
						return Redirect(true, "Your password has been saved", r);
					return RedirectToAction(true, "Your password has been saved", "Index", "Home");
				}
				ModelState.AddModelError("OldPassword", "Cannot set password; a password already exists for this user account");
			}

			return View();
		}

		public virtual ActionResult ForgotPassword()
		{
			if(CurrentUser.AccessLevel != AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");

			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		public virtual ActionResult ForgotPassword(string email)
		{
			if(CurrentUser.AccessLevel != AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");

			if(CurrentUser.SendPasswordReminder(email))
				return RedirectToAction(true, "Your password has been emailed to you", "Login");

			return RedirectToAction(false, "We don't have any users with that email address", "ForgotPassword");
		}


		[Authenticate]
		public virtual ActionResult Preferences()
		{
			return View(RequestContext.CurrentUser.User);
		}

		[AcceptVerbs(HttpVerbs.Post)]
		[Authenticate]
		public virtual ActionResult Preferences(string name, string username, string email, string pw1, string pw2)
		{
			name = (name ?? string.Empty).Trim();
			username = (username ?? string.Empty).Trim();
			email = (email ?? string.Empty).Trim();
			pw1 = (pw1 ?? string.Empty).Trim();
			pw2 = (pw2 ?? string.Empty).Trim();

			if(name.Length == 0)
				ModelState.AddModelError("Name", "We need a name - just your first name is fine");
			if(username.Length < 3)
				ModelState.AddModelError("Username", "Your username needs to be at least 3 characters in length");
			else if(_accountHandler.CheckForOtherUserByUsername(username, CurrentUser.User.ID))
				ModelState.AddModelError("Username", "Someone else already has that username");
			if(email.Length == 0)
				ModelState.AddModelError("Email", "Please enter your email address. We're not going to spam you, we just need to confirm that your email address is real!");
			else if(!email.IsEmailAddress())
				ModelState.AddModelError("Email", "The email address you entered doesn't seem to be a real email address");
			else if(_accountHandler.CheckForOtherUserByEmail(email, CurrentUser.User.ID))
				ModelState.AddModelError("Email", "Looks like you already created an account with that email address");
			if(pw1.Length > 0 && pw1.Length < 5)
				ModelState.AddModelError("pw1", "Your password needs to be at least 5 characters in length");
			else if(pw1 != pw2)
				ModelState.AddModelError("pw1", "The second password you typed in wasn't the same as the first one");

			if(!ModelState.IsValid)
				return View(CurrentUser.User);

			CurrentUser.User.Name = name;
			CurrentUser.User.Username = username;
			CurrentUser.User.Email = email;
			if(pw1.Length > 0)
				CurrentUser.User.SetPassword(pw1, WebsiteSettings.PublicKey);
			if(!CurrentUser.UpdateUser())
				return RedirectToAction(false, "There was an error saving your account preferences", "Index", "Home");

			return RedirectToAction(true, "Your account preferences have been saved", "Index", "Home");
		}

		public virtual ActionResult Register()
		{
			if(CurrentUser.AccessLevel != AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");
			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		public virtual ActionResult Register(string name, string username, string email, string pw1, string pw2)
		{
			if(CurrentUser.AccessLevel != AccessLevel.Anonymous)
				return RedirectToAction("Index", "Home");

			name = (name ?? string.Empty).Trim();
			username = (username ?? string.Empty).Trim();
			email = (email ?? string.Empty).Trim();
			pw1 = (pw1 ?? string.Empty).Trim();
			pw2 = (pw2 ?? string.Empty).Trim();

			if(name.Length == 0)
				ModelState.AddModelError("Name", "Your forgot to tell us your name");
			if(username.Length < 3)
				ModelState.AddModelError("Username", "Your username needs to be at least 3 characters in length");
			else if(_accountHandler.CheckForOtherUserByUsername(username, 0))
				ModelState.AddModelError("Username", "Someone else already has that username");
			if(email.Length == 0)
				ModelState.AddModelError("Email", "Please enter your email address. We're not going to spam you, we just need to confirm that your email address is real!");
			else if(!email.IsEmailAddress())
				ModelState.AddModelError("Email", "The email address you entered doesn't seem to be a real email address");
			else if(_accountHandler.CheckForOtherUserByEmail(email, 0))
				ModelState.AddModelError("Email", "Looks like you already created an account with that email address");
			if(pw1.Length < 5)
				ModelState.AddModelError("pw1", "Your password needs to be at least 5 characters in length");
			else if(pw1 != pw2)
				ModelState.AddModelError("pw1", "The second password you typed in wasn't the same as the first one");

			if(!ModelState.IsValid)
			{
				User user = new User();
				user.Name = name;
				user.Username = username;
				user.Email = email;
				return View(user);
			}
			CurrentUser.Register(name, username, pw1, email, 0, "Your account has been created", System.IO.File.ReadAllText(Server.MapPath("~/App_Data/email_welcome.txt")));
			return OnRegistrationComplete();
		}

		[NonAction]
		public virtual ActionResult OnRegistrationComplete()
		{
			const string msg = "Thanks for registering!";
			if(Request.QueryString["r"] != null)
				return Redirect(true, msg, Request.QueryString["r"]);
			return RedirectToAction(true, msg, "Index", "Home");
		}
	}
}
